home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / lib / ruby / 1.8 / complex.rb < prev    next >
Encoding:
Ruby Source  |  2009-08-03  |  12.8 KB  |  660 lines

  1. #
  2. #   complex.rb - 
  3. #       $Release Version: 0.5 $
  4. #       $Revision: 1.3 $
  5. #       $Date: 1998/07/08 10:05:28 $
  6. #       by Keiju ISHITSUKA(SHL Japan Inc.)
  7. #
  8. # ----
  9. #
  10. # complex.rb implements the Complex class for complex numbers.  Additionally,
  11. # some methods in other Numeric classes are redefined or added to allow greater
  12. # interoperability with Complex numbers.
  13. #
  14. # Complex numbers can be created in the following manner:
  15. # - <tt>Complex(a, b)</tt>
  16. # - <tt>Complex.polar(radius, theta)</tt>
  17. #   
  18. # Additionally, note the following:
  19. # - <tt>Complex::I</tt> (the mathematical constant <i>i</i>)
  20. # - <tt>Numeric#im</tt> (e.g. <tt>5.im -> 0+5i</tt>)
  21. #
  22. # The following +Math+ module methods are redefined to handle Complex arguments.
  23. # They will work as normal with non-Complex arguments.
  24. #    sqrt exp cos sin tan log log10
  25. #    cosh sinh tanh acos asin atan atan2 acosh asinh atanh
  26. #
  27.  
  28.  
  29. #
  30. # Numeric is a built-in class on which Fixnum, Bignum, etc., are based.  Here
  31. # some methods are added so that all number types can be treated to some extent
  32. # as Complex numbers.
  33. #
  34. class Numeric
  35.   #
  36.   # Returns a Complex number <tt>(0,<i>self</i>)</tt>.
  37.   #
  38.   def im
  39.     Complex(0, self)
  40.   end
  41.   
  42.   #
  43.   # The real part of a complex number, i.e. <i>self</i>.
  44.   #
  45.   def real
  46.     self
  47.   end
  48.   
  49.   #
  50.   # The imaginary part of a complex number, i.e. 0.
  51.   #
  52.   def image
  53.     0
  54.   end
  55.   alias imag image
  56.   
  57.   #
  58.   # See Complex#arg.
  59.   #
  60.   def arg
  61.     Math.atan2!(0, self)
  62.   end
  63.   alias angle arg
  64.   
  65.   #
  66.   # See Complex#polar.
  67.   #
  68.   def polar
  69.     return abs, arg
  70.   end
  71.   
  72.   #
  73.   # See Complex#conjugate (short answer: returns <i>self</i>).
  74.   #
  75.   def conjugate
  76.     self
  77.   end
  78.   alias conj conjugate
  79. end
  80.  
  81.  
  82. #
  83. # Creates a Complex number.  +a+ and +b+ should be Numeric.  The result will be
  84. # <tt>a+bi</tt>.
  85. #
  86. def Complex(a, b = 0)
  87.   if b == 0 and (a.kind_of?(Complex) or defined? Complex::Unify)
  88.     a
  89.   else
  90.     Complex.new( a.real-b.imag, a.imag+b.real )
  91.   end
  92. end
  93.  
  94. #
  95. # The complex number class.  See complex.rb for an overview.
  96. #
  97. class Complex < Numeric
  98.   @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
  99.  
  100.   undef step
  101.   undef div, divmod
  102.   undef floor, truncate, ceil, round
  103.  
  104.   def Complex.generic?(other) # :nodoc:
  105.     other.kind_of?(Integer) or
  106.     other.kind_of?(Float) or
  107.     (defined?(Rational) and other.kind_of?(Rational))
  108.   end
  109.  
  110.   #
  111.   # Creates a +Complex+ number in terms of +r+ (radius) and +theta+ (angle).
  112.   #
  113.   def Complex.polar(r, theta)
  114.     Complex(r*Math.cos(theta), r*Math.sin(theta))
  115.   end
  116.  
  117.   #
  118.   # Creates a +Complex+ number <tt>a</tt>+<tt>b</tt><i>i</i>.
  119.   #
  120.   def Complex.new!(a, b=0)
  121.     new(a,b)
  122.   end
  123.  
  124.   def initialize(a, b)
  125.     raise TypeError, "non numeric 1st arg `#{a.inspect}'" if !a.kind_of? Numeric
  126.     raise TypeError, "`#{a.inspect}' for 1st arg" if a.kind_of? Complex
  127.     raise TypeError, "non numeric 2nd arg `#{b.inspect}'" if !b.kind_of? Numeric
  128.     raise TypeError, "`#{b.inspect}' for 2nd arg" if b.kind_of? Complex
  129.     @real = a
  130.     @image = b
  131.   end
  132.  
  133.   #
  134.   # Addition with real or complex number.
  135.   #
  136.   def + (other)
  137.     if other.kind_of?(Complex)
  138.       re = @real + other.real
  139.       im = @image + other.image
  140.       Complex(re, im)
  141.     elsif Complex.generic?(other)
  142.       Complex(@real + other, @image)
  143.     else
  144.       x , y = other.coerce(self)
  145.       x + y
  146.     end
  147.   end
  148.   
  149.   #
  150.   # Subtraction with real or complex number.
  151.   #
  152.   def - (other)
  153.     if other.kind_of?(Complex)
  154.       re = @real - other.real
  155.       im = @image - other.image
  156.       Complex(re, im)
  157.     elsif Complex.generic?(other)
  158.       Complex(@real - other, @image)
  159.     else
  160.       x , y = other.coerce(self)
  161.       x - y
  162.     end
  163.   end
  164.   
  165.   #
  166.   # Multiplication with real or complex number.
  167.   #
  168.   def * (other)
  169.     if other.kind_of?(Complex)
  170.       re = @real*other.real - @image*other.image
  171.       im = @real*other.image + @image*other.real
  172.       Complex(re, im)
  173.     elsif Complex.generic?(other)
  174.       Complex(@real * other, @image * other)
  175.     else
  176.       x , y = other.coerce(self)
  177.       x * y
  178.     end
  179.   end
  180.   
  181.   #
  182.   # Division by real or complex number.
  183.   #
  184.   def / (other)
  185.     if other.kind_of?(Complex)
  186.       self*other.conjugate/other.abs2
  187.     elsif Complex.generic?(other)
  188.       Complex(@real/other, @image/other)
  189.     else
  190.       x, y = other.coerce(self)
  191.       x/y
  192.     end
  193.   end
  194.   
  195.   def quo(other)
  196.     Complex(@real.quo(1), @image.quo(1)) / other
  197.   end
  198.  
  199.   #
  200.   # Raise this complex number to the given (real or complex) power.
  201.   #
  202.   def ** (other)
  203.     if other == 0
  204.       return Complex(1)
  205.     end
  206.     if other.kind_of?(Complex)
  207.       r, theta = polar
  208.       ore = other.real
  209.       oim = other.image
  210.       nr = Math.exp!(ore*Math.log!(r) - oim * theta)
  211.       ntheta = theta*ore + oim*Math.log!(r)
  212.       Complex.polar(nr, ntheta)
  213.     elsif other.kind_of?(Integer)
  214.       if other > 0
  215.     x = self
  216.     z = x
  217.     n = other - 1
  218.     while n != 0
  219.       while (div, mod = n.divmod(2)
  220.          mod == 0)
  221.         x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image)
  222.         n = div
  223.       end
  224.       z *= x
  225.       n -= 1
  226.     end
  227.     z
  228.       else
  229.     if defined? Rational
  230.       (Rational(1) / self) ** -other
  231.     else
  232.       self ** Float(other)
  233.     end
  234.       end
  235.     elsif Complex.generic?(other)
  236.       r, theta = polar
  237.       Complex.polar(r**other, theta*other)
  238.     else
  239.       x, y = other.coerce(self)
  240.       x**y
  241.     end
  242.   end
  243.   
  244.   #
  245.   # Remainder after division by a real or complex number.
  246.   #
  247.   def % (other)
  248.     if other.kind_of?(Complex)
  249.       Complex(@real % other.real, @image % other.image)
  250.     elsif Complex.generic?(other)
  251.       Complex(@real % other, @image % other)
  252.     else
  253.       x , y = other.coerce(self)
  254.       x % y
  255.     end
  256.   end
  257.   
  258. #--
  259. #    def divmod(other)
  260. #      if other.kind_of?(Complex)
  261. #        rdiv, rmod = @real.divmod(other.real)
  262. #        idiv, imod = @image.divmod(other.image)
  263. #        return Complex(rdiv, idiv), Complex(rmod, rmod)
  264. #      elsif Complex.generic?(other)
  265. #        Complex(@real.divmod(other), @image.divmod(other))
  266. #      else
  267. #        x , y = other.coerce(self)
  268. #        x.divmod(y)
  269. #      end
  270. #    end
  271. #++
  272.   
  273.   #
  274.   # Absolute value (aka modulus): distance from the zero point on the complex
  275.   # plane.
  276.   #
  277.   def abs
  278.     Math.hypot(@real, @image)
  279.   end
  280.   
  281.   #
  282.   # Square of the absolute value.
  283.   #
  284.   def abs2
  285.     @real*@real + @image*@image
  286.   end
  287.   
  288.   #
  289.   # Argument (angle from (1,0) on the complex plane).
  290.   #
  291.   def arg
  292.     Math.atan2!(@image, @real)
  293.   end
  294.   alias angle arg
  295.   
  296.   #
  297.   # Returns the absolute value _and_ the argument.
  298.   #
  299.   def polar
  300.     return abs, arg
  301.   end
  302.   
  303.   #
  304.   # Complex conjugate (<tt>z + z.conjugate = 2 * z.real</tt>).
  305.   #
  306.   def conjugate
  307.     Complex(@real, -@image)
  308.   end
  309.   alias conj conjugate
  310.   
  311.   #
  312.   # Compares the absolute values of the two numbers.
  313.   #
  314.   def <=> (other)
  315.     self.abs <=> other.abs
  316.   end
  317.   
  318.   #
  319.   # Test for numerical equality (<tt>a == a + 0<i>i</i></tt>).
  320.   #
  321.   def == (other)
  322.     if other.kind_of?(Complex)
  323.       @real == other.real and @image == other.image
  324.     elsif Complex.generic?(other)
  325.       @real == other and @image == 0
  326.     else
  327.       other == self
  328.     end
  329.   end
  330.  
  331.   #
  332.   # Attempts to coerce +other+ to a Complex number.
  333.   #
  334.   def coerce(other)
  335.     if Complex.generic?(other)
  336.       return Complex.new!(other), self
  337.     else
  338.       super
  339.     end
  340.   end
  341.  
  342.   #
  343.   # FIXME
  344.   #
  345.   def denominator
  346.     @real.denominator.lcm(@image.denominator)
  347.   end
  348.   
  349.   #
  350.   # FIXME
  351.   #
  352.   def numerator
  353.     cd = denominator
  354.     Complex(@real.numerator*(cd/@real.denominator),
  355.         @image.numerator*(cd/@image.denominator))
  356.   end
  357.   
  358.   #
  359.   # Standard string representation of the complex number.
  360.   #
  361.   def to_s
  362.     if @real != 0
  363.       if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
  364.     if @image >= 0
  365.       @real.to_s+"+("+@image.to_s+")i"
  366.     else
  367.       @real.to_s+"-("+(-@image).to_s+")i"
  368.     end
  369.       else
  370.     if @image >= 0
  371.       @real.to_s+"+"+@image.to_s+"i"
  372.     else
  373.       @real.to_s+"-"+(-@image).to_s+"i"
  374.     end
  375.       end
  376.     else
  377.       if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
  378.     "("+@image.to_s+")i"
  379.       else
  380.     @image.to_s+"i"
  381.       end
  382.     end
  383.   end
  384.   
  385.   #
  386.   # Returns a hash code for the complex number.
  387.   #
  388.   def hash
  389.     @real.hash ^ @image.hash
  390.   end
  391.   
  392.   #
  393.   # Returns "<tt>Complex(<i>real</i>, <i>image</i>)</tt>".
  394.   #
  395.   def inspect
  396.     sprintf("Complex(%s, %s)", @real.inspect, @image.inspect)
  397.   end
  398.  
  399.   
  400.   #
  401.   # +I+ is the imaginary number.  It exists at point (0,1) on the complex plane.
  402.   #
  403.   I = Complex(0,1)
  404.   
  405.   # The real part of a complex number.
  406.   attr :real
  407.  
  408.   # The imaginary part of a complex number.
  409.   attr :image
  410.   alias imag image
  411.   
  412. end
  413.  
  414. class Integer
  415.  
  416.   unless defined?(1.numerator)
  417.     def numerator() self end
  418.     def denominator() 1 end
  419.  
  420.     def gcd(other)
  421.       min = self.abs
  422.       max = other.abs
  423.       while min > 0
  424.         tmp = min
  425.         min = max % min
  426.         max = tmp
  427.       end
  428.       max
  429.     end
  430.  
  431.     def lcm(other)
  432.       if self.zero? or other.zero?
  433.         0
  434.       else
  435.         (self.div(self.gcd(other)) * other).abs
  436.       end
  437.     end
  438.  
  439.   end
  440.  
  441. end
  442.  
  443. module Math
  444.   alias sqrt! sqrt
  445.   alias exp! exp
  446.   alias log! log
  447.   alias log10! log10
  448.   alias cos! cos
  449.   alias sin! sin
  450.   alias tan! tan
  451.   alias cosh! cosh
  452.   alias sinh! sinh
  453.   alias tanh! tanh
  454.   alias acos! acos
  455.   alias asin! asin
  456.   alias atan! atan
  457.   alias atan2! atan2
  458.   alias acosh! acosh
  459.   alias asinh! asinh
  460.   alias atanh! atanh  
  461.  
  462.   # Redefined to handle a Complex argument.
  463.   def sqrt(z)
  464.     if Complex.generic?(z)
  465.       if z >= 0
  466.     sqrt!(z)
  467.       else
  468.     Complex(0,sqrt!(-z))
  469.       end
  470.     else
  471.       if z.image < 0
  472.     sqrt(z.conjugate).conjugate
  473.       else
  474.     r = z.abs
  475.     x = z.real
  476.     Complex( sqrt!((r+x)/2), sqrt!((r-x)/2) )
  477.       end
  478.     end
  479.   end
  480.   
  481.   # Redefined to handle a Complex argument.
  482.   def exp(z)
  483.     if Complex.generic?(z)
  484.       exp!(z)
  485.     else
  486.       Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image))
  487.     end
  488.   end
  489.   
  490.   # Redefined to handle a Complex argument.
  491.   def cos(z)
  492.     if Complex.generic?(z)
  493.       cos!(z)
  494.     else
  495.       Complex(cos!(z.real)*cosh!(z.image),
  496.           -sin!(z.real)*sinh!(z.image))
  497.     end
  498.   end
  499.     
  500.   # Redefined to handle a Complex argument.
  501.   def sin(z)
  502.     if Complex.generic?(z)
  503.       sin!(z)
  504.     else
  505.       Complex(sin!(z.real)*cosh!(z.image),
  506.           cos!(z.real)*sinh!(z.image))
  507.     end
  508.   end
  509.   
  510.   # Redefined to handle a Complex argument.
  511.   def tan(z)
  512.     if Complex.generic?(z)
  513.       tan!(z)
  514.     else
  515.       sin(z)/cos(z)
  516.     end
  517.   end
  518.  
  519.   def sinh(z)
  520.     if Complex.generic?(z)
  521.       sinh!(z)
  522.     else
  523.       Complex( sinh!(z.real)*cos!(z.image), cosh!(z.real)*sin!(z.image) )
  524.     end
  525.   end
  526.  
  527.   def cosh(z)
  528.     if Complex.generic?(z)
  529.       cosh!(z)
  530.     else
  531.       Complex( cosh!(z.real)*cos!(z.image), sinh!(z.real)*sin!(z.image) )
  532.     end
  533.   end
  534.  
  535.   def tanh(z)
  536.     if Complex.generic?(z)
  537.       tanh!(z)
  538.     else
  539.       sinh(z)/cosh(z)
  540.     end
  541.   end
  542.   
  543.   # Redefined to handle a Complex argument.
  544.   def log(z)
  545.     if Complex.generic?(z) and z >= 0
  546.       log!(z)
  547.     else
  548.       r, theta = z.polar
  549.       Complex(log!(r.abs), theta)
  550.     end
  551.   end
  552.   
  553.   # Redefined to handle a Complex argument.
  554.   def log10(z)
  555.     if Complex.generic?(z)
  556.       log10!(z)
  557.     else
  558.       log(z)/log!(10)
  559.     end
  560.   end
  561.  
  562.   def acos(z)
  563.     if Complex.generic?(z) and z >= -1 and z <= 1
  564.       acos!(z)
  565.     else
  566.       -1.0.im * log( z + 1.0.im * sqrt(1.0-z*z) )
  567.     end
  568.   end
  569.  
  570.   def asin(z)
  571.     if Complex.generic?(z) and z >= -1 and z <= 1
  572.       asin!(z)
  573.     else
  574.       -1.0.im * log( 1.0.im * z + sqrt(1.0-z*z) )
  575.     end
  576.   end
  577.  
  578.   def atan(z)
  579.     if Complex.generic?(z)
  580.       atan!(z)
  581.     else
  582.       1.0.im * log( (1.0.im+z) / (1.0.im-z) ) / 2.0
  583.     end
  584.   end
  585.  
  586.   def atan2(y,x)
  587.     if Complex.generic?(y) and Complex.generic?(x)
  588.       atan2!(y,x)
  589.     else
  590.       -1.0.im * log( (x+1.0.im*y) / sqrt(x*x+y*y) )
  591.     end
  592.   end
  593.  
  594.   def acosh(z)
  595.     if Complex.generic?(z) and z >= 1
  596.       acosh!(z)
  597.     else
  598.       log( z + sqrt(z*z-1.0) )
  599.     end
  600.   end
  601.  
  602.   def asinh(z)
  603.     if Complex.generic?(z)
  604.       asinh!(z)
  605.     else
  606.       log( z + sqrt(1.0+z*z) )
  607.     end
  608.   end
  609.  
  610.   def atanh(z)
  611.     if Complex.generic?(z) and z >= -1 and z <= 1
  612.       atanh!(z)
  613.     else
  614.       log( (1.0+z) / (1.0-z) ) / 2.0
  615.     end
  616.   end
  617.  
  618.   module_function :sqrt!
  619.   module_function :sqrt
  620.   module_function :exp!
  621.   module_function :exp
  622.   module_function :log!
  623.   module_function :log
  624.   module_function :log10!
  625.   module_function :log10
  626.   module_function :cosh!
  627.   module_function :cosh
  628.   module_function :cos!
  629.   module_function :cos
  630.   module_function :sinh!
  631.   module_function :sinh
  632.   module_function :sin!
  633.   module_function :sin
  634.   module_function :tan!
  635.   module_function :tan
  636.   module_function :tanh!
  637.   module_function :tanh
  638.   module_function :acos!
  639.   module_function :acos
  640.   module_function :asin!
  641.   module_function :asin
  642.   module_function :atan!
  643.   module_function :atan
  644.   module_function :atan2!
  645.   module_function :atan2
  646.   module_function :acosh!
  647.   module_function :acosh
  648.   module_function :asinh!
  649.   module_function :asinh
  650.   module_function :atanh!
  651.   module_function :atanh
  652.   
  653. end
  654.  
  655. # Documentation comments:
  656. #  - source: original (researched from pickaxe)
  657. #  - a couple of fixme's
  658. #  - RDoc output for Bignum etc. is a bit short, with nothing but an
  659. #    (undocumented) alias.  No big deal.
  660.